package wangwenjun.phase1.reference.phantom;

import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.net.Socket;

/**
 * @author ChangLiang
 * @date 2020/6/17
 */
public class SocketCleaningTracker {

    /**
     * 定义ReferenceQueue
     */
    private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();

    static{
        new CleanerThread().start();
    }

    public static void track(Socket socket) {
        new Tracker(socket, queue);
    }


    private static class CleanerThread extends Thread{
        private CleanerThread() {
            super("socket-cleaning-tracker-cleaner-thread");
            /**
             * Cleaner 线程被设置为守护线程， 清理
             * 动作一般是系统的清理工作， 用于防止JVM 无法正常关闭，如同JVM 的GC 线程的作用
             * 一样
             */
            setDaemon(true);
        }

        @Override
        public void run() {
            while (true) {
                try {
                    // 当Tracker 被垃圾回收器回收时会加入Queue 中
                    // 不断地从ReferenceQueue 中remove Tracker 实例（ Tracker 是一个PhantomReference
                    //的子类）， 然后尝试进行最后的清理动作
                    Tracker tracker = (Tracker) queue.remove();
                    tracker.close();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Tracker 是一个PhantomReference 的子类
     */
    private static class Tracker extends PhantomReference<Object> {

        private final Socket socket;

        Tracker(Socket socket, ReferenceQueue<? super Object> queue) {
            super(socket, queue);
            this.socket = socket;
        }

        public void close() {
            try {
                socket.close();
            } catch (IOException e) {
                // note: 这里为了使底层资源的关闭不影响线程任务的结束
                // 这里捕获了Throwable异常（在关闭底层资源时出现的异常，视为不可恢复的异常，基本上没有针对该异常进行处理的必要）
                e.printStackTrace();
            }
        }
    }
}
